home *** CD-ROM | disk | FTP | other *** search
/ Sounds Terrific 2 / Sounds Terrific II (1996)(Weird Science)(Disc 1 of 2)[Amiga-PC].iso / archives / amiga / tracker_4_31.lzh / tracker / open.c < prev    next >
C/C++ Source or Header  |  1995-02-21  |  11KB  |  531 lines

  1. /* open.c 
  2.     vi:ts=3 sw=3:
  3.  */
  4.  
  5. /* Magic open file: path lookup and transparent decompression */
  6.  
  7. /* $Id: open.c,v 4.15 1995/02/21 21:13:16 espie Exp espie $ 
  8.  * $Log: open.c,v $
  9.  * Revision 4.15  1995/02/21  21:13:16  espie
  10.  * Cleaned up source. Moved minor pieces of code around.
  11.  *
  12.  * Revision 4.14  1995/02/21  17:54:32  espie
  13.  * Internal problem: buggy RCS. Fixed logs.
  14.  *
  15.  * Revision 4.9  1995/02/01  20:41:45  espie
  16.  * Added color.
  17.  *
  18.  * Revision 4.8  1995/02/01  16:39:04  espie
  19.  * Cleaned up rewind stuff.
  20.  * Fixed serious bug with read_file.
  21.  *
  22.  * Revision 4.7  1995/01/30  18:15:01  espie
  23.  * Implemented buffer for open_file and such !
  24.  *
  25.  *
  26.  * Revision 4.2  1994/07/04  14:00:06  espie
  27.  * External compression methods.
  28.  * A little more abstract, should work better
  29.  * Better amiga patterns.
  30.  * Amiga support.
  31.  * Added gzip/shorten.
  32.  * restore stty.
  33.  *
  34.  * Revision 1.5  1992/11/01  13:10:06  espie
  35.  * Cleaned up path handler, and some more bugs.
  36.  * Check for size now.
  37.  * Added path support. Transparent interface. We look up through the file
  38.  * list, which is small anyway.
  39.  */
  40.  
  41. #include "defs.h"
  42.  
  43. #include <ctype.h>
  44.  
  45. #include "extern.h"
  46.  
  47. ID("$Id: open.c,v 4.15 1995/02/21 21:13:16 espie Exp espie $")
  48.  
  49.  
  50. /* forward declarations */
  51. LOCAL struct exfile *do_open(struct exfile *file, char *fname, char *path);
  52.  
  53.  
  54.  
  55. /***
  56.  ***     Stuff for compression methods 
  57.  ***/
  58.  
  59. /* Max buffer length for reading compression methods */
  60. #define MAX_LENGTH 90
  61.  
  62.  
  63. /* automaton */
  64. #define END_OF_LINE 0
  65. #define BEGIN_OF_LINE 1
  66. #define IN_SPEC 2
  67. #define BEGIN_OF_COMMAND 3
  68. #define IN_COMMAND 4
  69.  
  70.  
  71. LOCAL void init_compression P((void));
  72. LOCAL void (*INIT)P((void)) = init_compression;
  73. extern int error;
  74.  
  75.  
  76.  
  77. /*** extended file structure:
  78.  ***        designed to be able to rewind pipes on a small length    (BUFSIZE) 
  79.  ***        in order to be able to retry lots of formats for cheap
  80.  ***/
  81. #define BUFSIZE 15000
  82. struct exfile
  83.    {
  84.    FILE *handle;                            /* the real Mc Coy */
  85.     unsigned char buffer[BUFSIZE];    /* we buffer only the file beginning */
  86.     int length;                                /* the length read in the buffer */
  87.     int pos;                                    /* current pos in the buffer */
  88.  
  89.         /* OO methods */
  90.    void (*close)P((struct exfile *f));    
  91.    void (*rewind)P((struct exfile *f));
  92.     int (*read)P((void *ptr, int size, int nitems, struct exfile *f));
  93.    int (*getcar)P((struct exfile *f));
  94.    int (*tell)P((struct exfile *f));
  95.  
  96.         /* kludge to reopen file */
  97.     char *name;
  98.     char *path;
  99.    };
  100.  
  101. /***
  102.  ***      the methods for buffered files 
  103.  ***/
  104. LOCAL int do_getchar(f)
  105. struct exfile *f;
  106.    {
  107.    int c;
  108.  
  109.     if (f->pos < BUFSIZE)
  110.         {
  111.         if (f->pos >= f->length)
  112.             {
  113.             error = FILE_TOO_SHORT;
  114.             return EOF;
  115.             }
  116.         else
  117.             return f->buffer[f->pos++];
  118.         }
  119.    if ((c = fgetc(f->handle)) == EOF)
  120.       error = FILE_TOO_SHORT;
  121.    else
  122.       f->pos++;
  123.    return c;
  124.    }
  125.  
  126. LOCAL int do_read(p, s, n, f)
  127. void *p;
  128. int s, n;
  129. struct exfile *f;
  130.     {
  131.     int total = s * n;
  132.     if (f->pos < BUFSIZE)
  133.         {
  134.         int remaining = f->length - f->pos;
  135.         if (remaining >= total)
  136.             {
  137.             memcpy(p, &(f->buffer[f->pos]), total);
  138.             f->pos += total;
  139.             return n;
  140.             }
  141.         else
  142.             {
  143.             memcpy(p, &(f->buffer[f->pos]), remaining);
  144.             total = remaining + 
  145.                     fread((char *)p+remaining, 1, total - remaining, f->handle);
  146.             f->pos += total;
  147.             return total/s;
  148.             }
  149.         }
  150.     else
  151.         {
  152.         total = fread(p, s, n, f->handle);
  153.         f->pos += total * s;
  154.         return total;
  155.         }
  156.     }
  157.  
  158.  
  159. LOCAL void do_rewind(f)
  160. struct exfile *f;
  161.     {
  162.     if (f->pos <= f->length)
  163.         f->pos = 0;
  164.     else
  165.         {
  166.         (*f->close)(f);
  167.         f = do_open(f, f->name, f->path);
  168.         }
  169.     }
  170.  
  171. LOCAL int do_tell(f)
  172. struct exfile *f;
  173.    {
  174.    return f->pos;
  175.    }
  176.  
  177. LOCAL void do_pclose(f)
  178. struct exfile *f;
  179.    {
  180.    pclose(f->handle);
  181.    }
  182.  
  183. LOCAL void do_fclose(f)
  184. struct exfile *f;
  185.    {
  186.    fclose(f->handle);
  187.    }
  188.  
  189. LOCAL struct exfile *init_buffered(f)
  190. struct exfile *f;
  191.     {
  192.     f->length = fread(f->buffer, 1, BUFSIZE, f->handle);
  193.     f->getcar = do_getchar;
  194.     f->tell = do_tell;
  195.     f->read = do_read;
  196.     f->rewind = do_rewind;
  197.     f->pos = 0;
  198.     return f;
  199.     }
  200.   
  201.  
  202. /***
  203.  ***    Compression methods database handling
  204.  ***/
  205.  
  206. /* compression methods we do know about.
  207.  * Important restriction: for the time being, the output
  208.  * must be a single module.
  209.  */
  210. struct compression_method
  211.    {
  212.    struct compression_method *next;
  213.    char *extension;
  214.    char *command;
  215.    };
  216.  
  217. LOCAL struct compression_method *read_method(f)
  218. FILE *f;
  219.    {
  220.    static char buffer[MAX_LENGTH + 1];
  221.    
  222.    while (fgets(buffer, MAX_LENGTH, f))
  223.       {
  224.       int state = BEGIN_OF_LINE;
  225.       int start, i;
  226.       char *spec = NULL, *command = NULL;
  227.       
  228.       for (i = 0; state != END_OF_LINE; i++)
  229.          {
  230.          switch(state)
  231.             {
  232.          case BEGIN_OF_LINE:
  233.             switch(buffer[i])
  234.                {
  235.             case ' ':
  236.             case '\t':
  237.                break;
  238.             case 0:
  239.             case '\n':
  240.             case '#':
  241.                state = END_OF_LINE;
  242.                break;
  243.             default:
  244.                start = i;
  245.                state = IN_SPEC;
  246.                }
  247.             break;
  248.          case IN_SPEC:
  249.             switch(buffer[i])
  250.                {
  251.             case ' ':
  252.             case '\t':
  253.                spec = malloc(i - start + 1);
  254.                strncpy(spec, buffer + start, i - start);
  255.                spec[i - start] = 0;
  256.                state = BEGIN_OF_COMMAND;
  257.                break;
  258.             case 0:
  259.             case '\n':
  260.                state = END_OF_LINE;
  261.                break;
  262.             default:
  263.                break;
  264.                }
  265.             break;
  266.          case BEGIN_OF_COMMAND:
  267.             switch (buffer[i])
  268.                {
  269.             case ' ':
  270.             case '\t':
  271.                break;
  272.             case 0:
  273.             case '\n':
  274.                state = END_OF_LINE;
  275.                free(spec);
  276.                break;
  277.             default:
  278.                state = IN_COMMAND;
  279.                start = i;
  280.                }
  281.             break;
  282.          case IN_COMMAND:
  283.             switch (buffer[i])
  284.                {
  285.             case 0:
  286.             case '\n':
  287.                command = malloc(i - start + 1);
  288.                strncpy(command, buffer + start, i - start);
  289.                command[i-start] = 0;
  290.                state = END_OF_LINE;
  291.             default:
  292.                break;
  293.                }
  294.             }
  295.          }      
  296.       if (command && spec)
  297.          {
  298.          struct compression_method *new;
  299.          
  300.          new = malloc(sizeof(struct compression_method));
  301.          new->next = 0;
  302.          new->extension = spec;
  303.          new->command = command;
  304.          return new;
  305.          }
  306.       }
  307.    return 0;
  308.    }
  309.       
  310.  
  311. LOCAL struct compression_method **read_methods(previous, f)
  312. struct compression_method **previous;
  313. FILE *f;
  314.    {
  315.    struct compression_method *method;
  316.    
  317.    if (f)
  318.       {
  319.       while (method = read_method(f))
  320.          {
  321.          *previous = method;
  322.          previous = &(method->next);
  323.          }
  324.       fclose(f);
  325.       }
  326.    return previous;
  327.    }
  328.       
  329.  
  330. LOCAL struct compression_method *comp_list;
  331.  
  332. LOCAL void init_compression()
  333.    {
  334.    char *fname;
  335.    FILE *f;
  336.    struct compression_method **previous;
  337.  
  338.    f = 0;
  339.    fname = getenv("TRACKER_COMPRESSION");
  340.    if (fname)
  341.       f = fopen(fname, "r");
  342.    if (!f)
  343.       {
  344.       fname = COMPRESSION_FILE;
  345.       f = fopen(fname, "r");
  346.       }
  347.    previous = read_methods(&comp_list, f);
  348.    }
  349.       
  350. /* Handling extensions.
  351.  */
  352. LOCAL int check_ext(s, ext)
  353. char *s, *ext;
  354.    {
  355.    int ext_len, s_len;
  356.    char *c;
  357.  
  358.    ext_len = strlen(ext);
  359.    s_len = strlen(s);
  360.    if (s_len < ext_len)
  361.       return FALSE;
  362.    for (c = s + s_len - ext_len; *c; c++, ext++)
  363.       if (tolower(*c) != tolower(*ext))
  364.          return FALSE;
  365.    return TRUE;
  366.    }
  367.  
  368. LOCAL int exist_file(fname)
  369. char *fname;
  370.    {
  371.    FILE *temp;
  372.  
  373.    temp = fopen(fname, READ_ONLY);
  374.    if (temp)
  375.       {
  376.       fclose(temp);
  377.       return TRUE;
  378.       }
  379.    else
  380.       return FALSE;
  381.    }
  382.  
  383. #ifndef MAXPATHLEN
  384. #define MAXPATHLEN 350
  385. #endif
  386.  
  387. /* note that find_file returns a STATIC value */
  388. LOCAL char *find_file(fname, path)
  389. char *fname;
  390. char *path;
  391.    {
  392.    char *sep;
  393.    static char buffer[MAXPATHLEN];
  394.    int len;
  395.  
  396.       /* first, check the current directory */
  397.    if (exist_file(fname))
  398.       return fname;
  399.    while(path)
  400.       {
  401.       sep = strchr(path, ':');
  402.       if (sep)
  403.          len = sep - path;
  404.       else
  405.          len = strlen(path);
  406.       if (len < MAXPATHLEN)
  407.          {
  408.          strncpy(buffer, path, len);
  409.          buffer[len] = '/';
  410.          if (len + strlen(fname) < MAXPATHLEN - 5)
  411.             {
  412.             strcpy(buffer + len + 1, fname);
  413.             puts(buffer);
  414.             if (exist_file(buffer))
  415.                return buffer;
  416.             }
  417.          }
  418.       if (sep)
  419.          path = sep + 1;
  420.       else
  421.             return NULL;
  422.       }
  423.     return NULL;
  424.    }
  425.  
  426. /* opening a file is bigger than it seems (much bigger) */
  427. LOCAL struct exfile *do_open(file, fname, path)
  428. struct exfile *file;
  429. char *fname;
  430. char *path;
  431.    {
  432.    struct compression_method *comp;
  433.  
  434.    INIT_ONCE;
  435.     
  436.     file->name = fname;
  437.     file->path = path;
  438.  
  439.    fname = find_file(fname, path);
  440.    if (!fname)
  441.       goto not_opened;
  442.          /* check for extension */
  443.    for (comp = comp_list; comp; comp = comp->next)
  444.       if (check_ext(fname, comp->extension))
  445.          {
  446.          char *pipe;
  447.          
  448.          pipe = malloc(strlen(comp->command) + strlen(fname) + 25);
  449.          if (!pipe)
  450.             goto not_opened;
  451.  
  452.          sprintf(pipe, comp->command, fname);
  453.          file->close = do_pclose;
  454.          file->handle = popen(pipe, READ_ONLY);
  455.          free(pipe);
  456.          if (file->handle)
  457.             return init_buffered(file);
  458.          else
  459.             goto not_opened;
  460.          }
  461.    file->close = do_fclose;
  462.    if (file->handle = fopen(fname, READ_ONLY))
  463.       return init_buffered(file);
  464.  
  465. not_opened:
  466.    free(file);
  467.    return NULL;
  468.    }
  469.  
  470.  
  471.  
  472.  
  473. /***
  474.  ***    The stubs that call the actual methods
  475.  ***/
  476.  
  477.  
  478. int getc_file(f)
  479. struct exfile *f;
  480.    {
  481.    return (*f->getcar)(f);
  482.    }
  483.  
  484. int read_file(p, s, n, f)
  485. void *p;
  486. int s, n;
  487. struct exfile *f;
  488.     {
  489.     return (*f->read)(p, s, n, f);
  490.     }
  491.  
  492. int tell_file(f)
  493. struct exfile *f;
  494.    {
  495.    return (*f->tell)(f);
  496.    }
  497.  
  498. void rewind_file(f)
  499. struct exfile *f;
  500.     {
  501.     (*f->rewind)(f);
  502.     }
  503.  
  504. struct exfile *open_file(fname, mode, path)
  505. char *fname;
  506. char *mode; /* right now, only mode "r" is supported */
  507. char *path; 
  508.     {
  509.     struct exfile *new;
  510.  
  511.    if (mode[0] != 'r' || mode[1] != 0)
  512.       return NULL;
  513.     new = (struct exfile *)malloc(sizeof(struct exfile));
  514.    if (new)
  515.         return do_open(new, fname, path);
  516.     else
  517.       return NULL;
  518.     }
  519.  
  520.  
  521. void close_file(file)
  522. struct exfile *file;
  523.    {
  524.     if (file)
  525.         {
  526.         (*file->close)(file);
  527.         free(file);
  528.         }
  529.    }
  530.  
  531.